AWS CDKでVPC、サブネット、EC2を作成してみる
はじめに
AWS上で何らかの検証を行うため、VPCとサブネットを用意し、その中にEC2インスタンスを作成することはしばしばあるかと思います。 これらをパッと作れるよう、以下のような点を考慮しつつAWS CDKで作成してみました。
- VPC、パブリックサブネット、プライベートサブネットを作成。それぞれのサブネットにEC2インスタンスを作成する。
- EC2インスタンスにはSession Managerで接続できるようにする。
- セキュリティグループを作成するが、Ingressは何も許可しない(必要な時に手動で許可する想定)。
- CDKのbootstrapコマンドで使用するバケット名を指定できるようにする。
- CDKのToolkitのスタック名を指定できるようにする。
- CloudFormationスタックに説明を入れる。
以下、作成した時に行ったことやソースについて書きたいと思います。
実装について
前提条件
AWS CDKを実行するにあたり、AWS CLIやNode.js、CDKなど必要なものはローカルにインストール済みであるものとします。 今回使用したCDKのバージョンは「2.56.0」となります。
$ cdk --version 2.56.0 (build 1485f48)
プロジェクト作成
ローカルに作業用のフォルダを作成します。今回は「cdk-vpc-ec2」というフォルダ名としました。
$ mkdir cdk-vpc-ec2 $ cd cdk-vpc-ec2
以下のコマンドを実行してプロジェクトを作成します。
$ cdk init sample-app --language typescript
実装したソース
AWS CDKのソースは以下のようになります。
cdk-vpc-ec2.ts
#!/usr/bin/env node import * as cdk from 'aws-cdk-lib'; import { CdkVpcEc2Stack } from '../lib/cdk-vpc-ec2-stack'; import { DefaultStackSynthesizer } from 'aws-cdk-lib'; const app = new cdk.App(); new CdkVpcEc2Stack(app, 'CdkVpcEc2Stack', { synthesizer: new DefaultStackSynthesizer({ fileAssetsBucketName: 'cdk-vpc-ec2-assets', // bootstrapのバケット名を指定 }), description: 'This is a cdk-vpc-ec2-sample-stack', // CloudFormationスタックに説明を追加 });
cdk-vpc-ec2-stack.ts
import { Duration, Stack, StackProps } from 'aws-cdk-lib'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as iam from 'aws-cdk-lib/aws-iam'; import { CfnOutput } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkVpcEc2Stack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // バケット const bucket = new s3.Bucket(this, 'SampleBucket', { blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, encryption: s3.BucketEncryption.S3_MANAGED, bucketName: "cdk-vpc-ec2-sample-bucket", }); // VPC const vpc = new ec2.Vpc(this, 'SampleVpc', { ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), vpcName: 'cdk-sample-vpc' }); // セキュリティグループ const securityGroup = new ec2.SecurityGroup(this, 'SampleSecurityGroup', { vpc: vpc, securityGroupName: 'cdk-vpc-ec2-security-group', }); // (Session Mangerを使うための)IAMロール const instanceRole = new iam.Role(this, 'SampleRole', { assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName( "AmazonSSMManagedInstanceCore" ), ], description: 'cdk-vpc-ec2-instance-role', }); // EC2インスタンス作成 const createInstance = (id: string, name: string, subnet: ec2.SubnetSelection) : ec2.Instance => { return new ec2.Instance(this, id, { vpc, vpcSubnets: subnet, instanceType: new ec2.InstanceType(this.node.tryGetContext('instanceType')), machineImage: ec2.MachineImage.latestAmazonLinux({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, }), securityGroup: securityGroup, role: instanceRole, instanceName: name }); }; const instance1 = createInstance('SampleInstance1', 'cdk-vpc-ec2-instance1', vpc.selectSubnets({ subnetType: ec2.SubnetType.PUBLIC })); const instance2 = createInstance('SampleInstance2', 'cdk-vpc-ec2-instance2', vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS })); // CloudFormationに出力 new CfnOutput(this, 'S3', { value: bucket.bucketName }); new CfnOutput(this, 'VPC', { value: vpc.vpcId }); new CfnOutput(this, 'Security Group', { value: securityGroup.securityGroupId }); new CfnOutput(this, 'EC2Instance1', { value: instance1.instanceId }); new CfnOutput(this, 'EC2Instance2', { value: instance2.instanceId }); } }
cdk.json
{ (中略) "context": { (中略。context内に以下をインスタンスタイプの定義を追記) "instanceType": "t2.micro" } }
コメントに書いてあるように、bootstrapで使用する任意のバケット名を指定しています。 また作成されるCloudFormationに説明を追加したり、出力値に作成したリソースの名称等を出力するようにしています。
実行したコマンド
bootstrapではバケット名、ToolKitのスタック名を指定しました。以下のようなコマンドとなります。
$ cdk bootstrap \ --bootstrap-bucket-name cdk-vpc-ec2-assets \ --toolkit-stack-name cdk-vpc-ec2-toolkit \
diffやdeployなどのコマンドは特に引数などは必要ありません。
$ cdk diff $ cdk deploy
実行結果
CDKのコマンドを実行するとCloudFormationやリソースが作成されるかと思います。以下に作成されたもののキャプチャの一部を挙げて起きます。
スタックの説明
スタックの出力値
インスタンス
まとめ
個人的にしばしば使うリソースをAWS CDKを使って作ってみました。何かの役にたてば幸いです。